package com.carnation.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import com.carnation.bean.FileInfo;
import com.carnation.bean.LocalFileInfo;
import com.carnation.bean.Menu;
import com.carnation.bean.User;
import com.carnation.service.FileService;
import com.carnation.utils.MenuFileUtril;

public class FileServiceImpl implements FileService{
	
	MenuFileUtril menuFileUtril = new MenuFileUtril();
	private String rootPath = menuFileUtril.getRootPath();
	private Logger logger = Logger.getLogger(FileServiceImpl.class);
	private ReentrantLock lock = new ReentrantLock();
	
	@Override
	public boolean createDirectory(Menu menu,User user){
		String directory = rootPath + menu.getId();
		File file = new File(directory);
		if(file.exists() || file.isFile()){
			return false;
		}
		if(file.mkdir()){
			String path = menuFileUtril.getFileInfoDBNameWithPath();
			SAXReader reader = new SAXReader();
			reader.setEncoding("UTF-8");
			lock.tryLock();
			try{
				Document document = reader.read(new File(path));
				Element e = (Element)document.selectSingleNode("/root/catalog[@id='" + menu.getId() +"']");
				if(e != null){
					logger.error("目录节点已存在");
					return false;
				}
				Element root = document.getRootElement();
				Element catalog = root.addElement("catalog");
				SimpleDateFormat formart = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				catalog.addAttribute("id", menu.getId());
				catalog.addAttribute("creator", user.getUserName());
				catalog.addAttribute("createTime", formart.format(new Date()));
				OutputFormat outputFormat = OutputFormat.createPrettyPrint();
				outputFormat.setEncoding("UTF-8");
				XMLWriter writer = new XMLWriter(new FileOutputStream(new File(menuFileUtril.getFileInfoDBNameWithPath())), outputFormat);
				writer.write(document);
				writer.close();
				return true;
			}
			catch(Exception e){
				logger.error("读取或写fileInfoDB文件出错",e);
				return false;
			}
			finally{
				lock.unlock();
			}
		}
		else{
			return false;
		}
	}
	
	@Override
	public Map<String,Long> getFileNameListByCatalogId(String catalogId){
		if(catalogId == null || catalogId.isEmpty()){
			return new HashMap<String,Long>();
		}
		try{
			SAXReader saxReader = new SAXReader();
			saxReader.setEncoding("UTF-8");
			String path = menuFileUtril.getFileInfoDBNameWithPath();
			Document document = saxReader.read(new File(path));
			Element target = (Element)document.selectSingleNode("/root/catalog[@id='" + catalogId + "']");
			if(target == null ){
				return new HashMap<String,Long>();
			}
			Map<String, Long> map = new HashMap<String,Long>();
			@SuppressWarnings("rawtypes")
			Iterator fileElements = target.elements("file").iterator();
			while(fileElements.hasNext()){
				Element e = (Element)fileElements.next();
				String name = e.attributeValue("name");
				Long size = Long.valueOf(e.attributeValue("size"));
				map.put(name, size);
			}
			return map;
		}
		catch(Exception e){
			logger.error("获取文件信息错误",e);
			return new HashMap<String,Long>();
		}
	}
	
	@Override
	public List<FileInfo> getFileInfoListByCondition(String catalogId,String name,String user,String start,String end,String desc,String remark){
		if(catalogId == null || catalogId.isEmpty()){
			return new ArrayList<FileInfo>();
		}
		try{
			SAXReader saxReader = new SAXReader();
			saxReader.setEncoding("UTF-8");
			String path = menuFileUtril.getFileInfoDBNameWithPath();
			Document document = saxReader.read(new File(path));
			Element target = (Element)document.selectSingleNode("/root/catalog[@id='" + catalogId + "']");
			if(target == null ){
				return new ArrayList<FileInfo>();
			}
			List<FileInfo> list = new ArrayList<FileInfo>();
			@SuppressWarnings("rawtypes")
			Iterator fileElements = target.elements("file").iterator();
			while(fileElements.hasNext()){
				boolean flag =true;
				Element e = (Element)fileElements.next();
				String filename = e.attributeValue("name");
				if(name != null && !name.isEmpty()){
					if(!filename.toLowerCase().contains(name.toLowerCase())){
						flag =false;
						continue;
					}
				}
				String uploaduser = e.attributeValue("uploadUser");
				if(user != null && !user.isEmpty()){
					if(!uploaduser.toLowerCase().contains(user.toLowerCase())){
						flag =false;
						continue;
					}
				}
				String uploadtime = e.attributeValue("uploadTime");
				SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
				if(start != null || end != null){
					boolean contain = getDateTimeContains(start, end, format.parse(uploadtime));
					if(!contain){
						continue;
					}
				}
				String description = e.attributeValue("description");
				if(desc != null && !desc.isEmpty()){
					if(!description.toLowerCase().contains(desc.toLowerCase())){
						continue;
					}
				}
				String fileremark = e.attributeValue("remark");
				if(remark != null && !remark.isEmpty()){
					if(!fileremark.toLowerCase().contains(remark.toLowerCase())){
						continue;
					}
				}
				long size = Long.parseLong(e.attributeValue("size"));
				String type = e.attributeValue("type");
				if(flag){
					FileInfo fileInfo = new FileInfo(catalogId, filename, uploaduser, uploadtime, description, fileremark,size,type);
					list.add(fileInfo);
				}
			}
			return list;
		}
		catch(Exception e){
			logger.error("获取文件信息错误",e);
			return new ArrayList<FileInfo>();
		}
	}
	
	private boolean getDateTimeContains(String start,String end,Date item){
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		if(start != null && !start.isEmpty() && end != null && !end.isEmpty()){
			try{
				Date startDate = format.parse(start);
				Date endDate = format.parse(end);
				return endDate.after(item) && startDate.before(item);
			}
			catch(ParseException e){
				logger.error("传入参数有误3",e);
				return true;
			}
		}
		else if(start !=null && !start.isEmpty() && (end == null || end.isEmpty())){
			
			try {
				Date startDate = format.parse(start);
				return startDate.before(item);
			} catch (ParseException e) {
				logger.error("传入参数有误1");
				return true;
			}
		}
		else if((start == null || start.isEmpty()) && end != null && !end.isEmpty()){
			try{
				Date endDate = format.parse(end);
				return endDate.after(item);
			}
			catch(ParseException e){
				logger.error("传入参数有误2");
				return true;
			}
		}
		else{
			return true;
		}
	}
	
	@Override
	public File findFileByNameAndCatalogId(String name,String catalogId){
		File file = new File(rootPath);
		File[] directoryList = file.listFiles();
		File target = null;
		if(directoryList == null || directoryList.length == 0){
			logger.error("存储跟路径下没有这个文件");
			return null;
		}
		for(File f :directoryList){
			if(f.getName().contains(catalogId)){
				target =f;
				break;
			}
		}
		if(target == null){
			logger.error("找不到对应的文件夹");
			return null;
		}
		File[] fileList = target.listFiles();
		for(File f : fileList){
			if(f.getName().equals(name)){
				return f;
			}
		}
		return null;
		
	}
	
	@Override
	public boolean checkFileExistByCatalogIdAndName(String catalogId,String name) throws Exception{
		String fileDB = menuFileUtril.getFileInfoDBNameWithPath();
		SAXReader reader = new SAXReader();
		reader.setEncoding("UTF-8");
		Document document = reader.read(new File(fileDB));
		Element catalog = (Element)document.selectSingleNode("/root/catalog[@id='" + catalogId + "']");
		if(catalog == null){
			logger.error("目录不存在，系统性错误");
			throw new Exception("目录不存在，系统性错误");
		}
		@SuppressWarnings("rawtypes")
		Iterator files = catalog.elementIterator("file");
		while(files.hasNext()){
			Element file = (Element)files.next();
			if(file.attributeValue("name").equals(name)){
				return true;
			}
		}
		return false;
	}
	
	@Override
	public String getStorePathByCatalogId(String catalogId)throws Exception{
		String path = menuFileUtril.getRootPath();
		File root = new File(path);
		File[] catalogFiles = root.listFiles();
		File target = null;
		for(File catalog : catalogFiles){
			if(catalog.getName().contains(catalogId)){
				target = catalog;
				break;
			}
		}
		if(target == null){
			throw new Exception("没有找到对应菜单的文件夹");
		}
		else {
			return target.getAbsolutePath();
		}
	}
	
	@Override
	public void writeFileInfo(FileInfo fileInfo) throws Exception{
		if(fileInfo.getCatalogId() == null || fileInfo.getCatalogId().isEmpty()){
			throw new Exception("传入的FILEINFO是错误的");
		}
		SAXReader reader = new SAXReader();
		reader.setEncoding("UTF-8");
		Document document = reader.read(new File(menuFileUtril.getFileInfoDBNameWithPath()));
		Element catalog = (Element)document.selectSingleNode("/root/catalog[@id='" + fileInfo.getCatalogId() + "']");
		Element file = catalog.addElement("file");
		file.addAttribute("name", fileInfo.getName());
		file.addAttribute("uploadUser", fileInfo.getUploadUser());
		file.addAttribute("uploadTime", fileInfo.getUploadTime());
		file.addAttribute("description", fileInfo.getDescription());
		file.addAttribute("remark", fileInfo.getRemark());
		file.addAttribute("size", Long.toString(fileInfo.getSize()));
		file.addAttribute("type", fileInfo.getType());
		lock.tryLock();
		try{
			OutputFormat format = OutputFormat.createPrettyPrint();
			format.setEncoding("UTF-8");
			XMLWriter writer = new XMLWriter(new FileOutputStream(new File(menuFileUtril.getFileInfoDBNameWithPath())), format);
			writer.write(document);
			writer.close();
		}
		catch(Exception e){
			logger.error("写失败",e);
		}
		finally{
			lock.unlock();
		}
	}

	@Override
	public boolean deleteFile(String catalogId,String filename){
		lock.tryLock();
		try{
			SAXReader reader = new SAXReader();
			reader.setEncoding("UTF-8");
			Document document = reader.read(new File(menuFileUtril.getFileInfoDBNameWithPath()));
			Element catalog = (Element)document.selectSingleNode("/root/catalog[@id='"+ catalogId + "']");
			Element target = null;
			@SuppressWarnings("rawtypes")
			Iterator files = catalog.elementIterator("file");
			while(files.hasNext()){
				Element file = (Element)files.next();
				if(file.attributeValue("name").equals(filename)){
					target = file;
					break;
				}
			}
			if(target == null){
				logger.error("找不到对应的文件");
				return false;
			}
			else{
				catalog.remove(target);
				OutputFormat format = OutputFormat.createPrettyPrint();
				format.setEncoding("UTF-8");
				XMLWriter writer = new XMLWriter(new FileOutputStream(new File(menuFileUtril.getFileInfoDBNameWithPath())), format);
				writer.write(document);
				writer.close();
				File root = new File(menuFileUtril.getRootPath());
				File targetCatalog = null;
				File[] catalogFiles = root.listFiles();
				for(File f :catalogFiles){
					if(f.getName().contains(catalogId)){
						targetCatalog = f;
						break;
					}
				}
				if(targetCatalog == null){
					logger.error("没有找到存储的catalog文件夹");
					return false;
				}
				else{
					File[] filesOfCatalog = targetCatalog.listFiles();
					for(File f :filesOfCatalog){
						if(f.getName().equals(filename)){
							f.delete();
							logger.info("删除文件成功");
							return true;
						}
					}
					return false;
				}
			}
		}
		catch(Exception e){
			logger.error("在删除文件时出错",e);
			return false;
		}
		finally{
			lock.unlock();
		}
	}

	@Override
	public List<String> getAllCatalogId(){
		List<String> list = new ArrayList<String>();
		try {
			SAXReader reader = new SAXReader();
			reader.setEncoding("UTF-8");
			Document document = reader.read(new File(menuFileUtril.getFileInfoDBNameWithPath()));
			System.out.println(menuFileUtril.getFileNameWithPath());
			Element root = document.getRootElement();
			System.out.println(root.elements("catalog").size());
			@SuppressWarnings("rawtypes")
			Iterator catalogs = root.elements("catalog").iterator();
			while(catalogs.hasNext()){
				Element e = (Element)catalogs.next();
				list.add(e.attributeValue("id"));
			}
			return list;
		} catch (Exception e) {
			logger.error("获取文件夹名称列表时出错",e);
			return new ArrayList<String>();
		}
	}

	@Override
	public String getRealPath(String fakePath) {
		if(fakePath == null || fakePath.isEmpty()){
			return null;
		}
		File file = new File(menuFileUtril.getRootPath());
		String realpath = file.getAbsolutePath();
		String[] parts = fakePath.split("/");
		for(String path :parts){
			file = new File(realpath,path);
			if(!file.exists()){
				return null;
			}
			realpath =  file.getAbsolutePath();
		}
		return realpath;
	}

	@Override
	public List<LocalFileInfo> getLocalFileInfoByRealPath(String path) {
		List<LocalFileInfo> list = new ArrayList<LocalFileInfo>();
		LocalFileInfo l = new LocalFileInfo();
		l.setFileName("..");
		list.add(l);
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		File file = new File(path);
		File[] files =file.listFiles();
		for(File f :files){
			LocalFileInfo localFileInfo = new LocalFileInfo(f.getName(), getFileType(f), f.length(), format.format(f.lastModified()));
			list.add(localFileInfo);
		}
		return list;
	}
	
	private String getFileType(File file){
		if(file.isDirectory()){
			return "文件夹";
		}
		else if(file.isFile()){
			return "文件";
		}
		else{
			return "未知类型";
		}
	}

	@Override
	public InputStream getFileInputStream(String realPath, String filename) {
		File file = new File(realPath,filename);
		if(!file.exists()||!file.isFile()){
			return null;
		}
		try {
			InputStream is = new FileInputStream(file);
			return is;
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
	}
}
